#include "MidiTrack.h"

MidiTrack::MidiTrack(const std::vector<uint8_t> &data) {
    uint64_t timSum = 0;
    auto it = data.begin();
    uint8_t LastMidiEventCode = 0;
    do {
        bool flag = true;
        uint32_t DeltaTime = 0;
        while (flag) {
            uint8_t t = *it++;
            flag = ((t & 0x80) == 0x80);
            DeltaTime = DeltaTime << 7 | (t & 0x7f);
        }
        timSum += DeltaTime;
        printf("DeltaTime = %04X, ", DeltaTime);

        uint8_t MidiEventCode = *it++;
        sw:
        switch ((MidiEventCode >> 4) & 0x0f) {
            case 0x8: {
                uint8_t Note = *it++;
                uint8_t dynamics = *it++;
                printf("UP   %02X, %02X\n", Note, dynamics);
                events.push_back({DeltaTime, MidiEventCode, Note, dynamics});
                break;
            }
            case 0x9: {
                uint8_t Note = *it++;
                uint8_t dynamics = *it++;
                printf("DOWN %02X, %02X\n", Note, dynamics);
                events.push_back({DeltaTime, MidiEventCode, Note, dynamics});
                break;
            }
            case 0xA: {
                uint8_t Note = *it++;
                uint8_t dynamics = *it++;
                events.push_back({DeltaTime, MidiEventCode, Note, dynamics});
                break;
            }
            case 0xB: {
                uint8_t ControllerCode = *it++;
                uint8_t ControllerPara = *it++;
                printf("ControllerCode = %02X, ControllerPara = %d\n", ControllerCode, ControllerPara);
                events.push_back({DeltaTime, MidiEventCode, ControllerCode, ControllerPara});
                break;
            }
            case 0xC: {
                uint8_t Instruments = *it++;
                events.push_back({DeltaTime, MidiEventCode, Instruments});
                break;
            }
            case 0xD: {
                uint8_t channel = *it++;
                events.push_back({DeltaTime, MidiEventCode, channel});
                break;
            }
            case 0xE: {
                uint8_t Pitch = *it++;
                uint8_t PitchDiv = *it++;
                events.push_back({DeltaTime, MidiEventCode, Pitch, PitchDiv});
                break;
            }
            case 0xF: {
                if (MidiEventCode == 0xFF) {
                    uint8_t CodeType = *it++;
                    uint8_t CodeSize = *it++;
                    if(CodeType == 0x2f && CodeSize == 0x00) {
                        printf("END, timSum = %lld\n", timSum);
                        return;
                    }
                    std::vector<uint8_t> d(it, it + CodeSize);
                    it += CodeSize;
                    printf("CodeType = %02X, CodeSize = %d\n", CodeType, CodeSize);
                    events.push_back({DeltaTime, MidiEventCode, d});
                } else {
                    uint8_t SysCodeSize = *it++;
                    std::vector<uint8_t> d(it, it + SysCodeSize);
                    it += SysCodeSize;
                    events.push_back({DeltaTime, MidiEventCode, d});
                }
                break;
            }
            default: {
                MidiEventCode = LastMidiEventCode;
                it--;
                goto sw;
            }
        }
        LastMidiEventCode = MidiEventCode;
    } while (it != data.end());
}
